package com.sdp.right.excel.exportExcel;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdp.core.bizc.annotation.ViewColumn;
import com.sdp.core.bizc.db.IViewQuery;
import com.sdp.core.bizc.db.Query;
import com.sdp.core.bizc.vo.DataCenter;
import com.sdp.right.db.sys_dict.service.ISysDictService;
import com.sdp.right.db.sys_import_template.service.ISysImportTemplateService;
import com.sdp.right.db.sys_import_template_detail.service.ISysImportTemplateDetailService;
import com.sdp.right.entity.SysImportTemplate;
import com.sdp.right.entity.SysImportTemplateDetail;
import com.sdp.right.excel.style.ExcelWidthStyleStrategy;
import com.sdp.right.utils.RightConstants;

@RestController
@RequestMapping("/excel/ExportExcelControl")
public class ExportExcelControl {

	@Autowired
	private Query query;
	
	@Autowired
	private ApplicationContext applicationContext;
	
	@Autowired
	private ISysImportTemplateService iSysImportTemplateService;
	
	@Autowired
	private ISysImportTemplateDetailService iSysImportTemplateDetailService;
	
	@Autowired
	private ISysDictService iSysDictService;
	
	/**
	 * 导入数据，最大单元格数
	 */
	private int maxCellCount = 200000;
	
	
	
	/**
	 * 数据导出
	 * @param request
	 * @param response
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@PostMapping(value = "/excelExport")
	public void excelImport(HttpServletRequest request, HttpServletResponse response) {
		String templateId = request.getParameter("templateId");
		String checkedFields = request.getParameter("checkedFields");
		String dataCenter = request.getParameter("dataCenter");
		DataCenter dc = new DataCenter();
		if (StringUtils.isEmpty(templateId)) {
			downloadException(response, "请指定数据模板");
			return;
		}
		
		if (StringUtils.isEmpty(checkedFields)) {
			downloadException(response, "请指定导出的列");
			return;
		}
		if(!StringUtils.isEmpty(dataCenter)) {
			dc = JSON.parseObject(dataCenter, DataCenter.class);
		}
		
		// 获取模板信息
		SysImportTemplate template = iSysImportTemplateService.querySysImportTemplateById(templateId);
		if (template == null) {
			downloadException(response, "制定的模板信息不存在");
			return;
		}
		
		//得到标题
		List<String> headers = new ArrayList<>();
		Map<String,SysImportTemplateDetail> detailMap = new HashMap<>();
		List<SysImportTemplateDetail> templateDetailList = JSON.parseArray(checkedFields, SysImportTemplateDetail.class);
		for(SysImportTemplateDetail sitd : templateDetailList) {
			headers.add(sitd.getDbField());
			detailMap.put(sitd.getFieldName(), sitd);
		}
		
		
		
		try {
			boolean isView = false;
			Class<?> clazz = Class.forName(template.getEntityClassName());
			Class<?> serviceClazz = Class.forName(template.getServiceClassName());
			
			Field[] fields = clazz.getDeclaredFields();
			for(int i=0;i<fields.length;i++) {
				if(fields[i].getAnnotation(ViewColumn.class)!=null) {
					isView = true;
					break;
				}
			}
			
			
			//查询数据
			List<?> li = new ArrayList<>();
			Object serviceImpl = applicationContext.getBean(serviceClazz);
			int count = 0;
			if(ExportExcelHandle.class.isAssignableFrom(serviceClazz)) {
				//如果是指定HANDLE 进行查询数据，需要将查询的列传入
				dc.setSelectColumns(headers.toArray(new String[headers.size()]));
				count = ((ExportExcelHandle)serviceImpl).queryCount(request, response,dc);
			}else if(isView) {
				count = query.viewCount((IViewQuery)serviceImpl, clazz, dc, new QueryWrapper<T>());
			}else {
				count = query.count((IService<T>)serviceImpl,clazz, dc);
			}
			
			if(count*headers.size()>maxCellCount) {
				downloadException(response, "导出数据量过大（最多不能超过"+maxCellCount+"）个单元格");
				return;
			}
			
			//得到要查的字段信息，不能放到查询count之前执行
			dc.setSelectColumns(headers.toArray(new String[headers.size()]));
			if(ExportExcelHandle.class.isAssignableFrom(serviceClazz)) {
				li = ((ExportExcelHandle)serviceImpl).queryList(request, response,dc);
			}else if(isView) {
				li = query.viewList((IViewQuery)serviceImpl, clazz, dc, new QueryWrapper<T>());
			}else{
				//当初封装的，传入的是创建的对象
				li = query.list((IService<T>)serviceImpl, clazz, dc);
			}
			
			if(li==null || li.size()==0) {
				downloadException(response, "数据不存在");
				return;
			}

			
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			String fileName = URLEncoder.encode(template.getTemplateName(), "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			EasyExcel.write(response.getOutputStream()).head(templateHead(templateDetailList)).autoCloseStream(Boolean.FALSE).sheet().registerWriteHandler(new ExcelWidthStyleStrategy()).doWrite(dataFormat(li,templateDetailList));
		} catch (Exception e) {
			e.printStackTrace();
			downloadException(response, e.getMessage());
		}
	}
	
	
	private List<List<Object>> dataFormat(List<?> dataList,List<SysImportTemplateDetail> templateDetailList) {
		List<List<Object>> resultList = new ArrayList<List<Object>>();
		JSONObject oldObj = new JSONObject();
		DateTimeFormatter dateTimeFormatter = null;
		Map<String,Map<String,String>> dictInfo = new HashMap<String, Map<String,String>>();
		for(int i=0;i<dataList.size();i++) {
			List<Object> newObj = new ArrayList<Object>();
			oldObj = JSONObject.parseObject(JSON.toJSONString(dataList.get(i)));
			for(SysImportTemplateDetail sitd : templateDetailList) {
				if(oldObj.containsKey(sitd.getFieldName())) {
					if(sitd.getFieldType().toLowerCase().indexOf("date")>-1) {
						//日期
						if(StringUtils.isEmpty(sitd.getDateFormat())) {
							newObj.add(oldObj.get(sitd.getFieldName()));
							continue;
						}
						//格式化
						dateTimeFormatter = DateTimeFormatter.ofPattern(sitd.getDateFormat());
						newObj.add(dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(oldObj.getLongValue(sitd.getFieldName())), ZoneId.systemDefault())));
						
					}else if(!StringUtils.isEmpty(sitd.getDictCode()) &&  "class java.lang.String".equals(sitd.getFieldType())) {
						//是下拉
						if(StringUtils.isEmpty(sitd.getItemText()) || StringUtils.isEmpty(sitd.getItemValue())) {
							newObj.add(oldObj.get(sitd.getFieldName()));
							continue;
						}
						
						
						if(!dictInfo.containsKey(sitd.getDictCode())) {
							//得到下拉信息
							List<Object> dictList = iSysDictService.getDictInfo(sitd.getDictCode(), new String[] {});
							if(dictList!=null && dictList.size()>0) {
								//将下拉数据源转为MAP
								Map<String,String> dictMap = new HashMap<String, String>();
								filterDictText(dictMap,dictList, oldObj.getString(sitd.getFieldName()), sitd.getItemText(), sitd.getItemValue());
								dictInfo.put(sitd.getDictCode(), dictMap);
							}
						
						}
						if(dictInfo.get(sitd.getDictCode())!=null && dictInfo.get(sitd.getDictCode()).containsKey(oldObj.getString(sitd.getFieldName()))) {
							newObj.add(dictInfo.get(sitd.getDictCode()).get(oldObj.getString(sitd.getFieldName())));
						}else {
							newObj.add(oldObj.get(sitd.getFieldName()));
						}
						
						
					}else {
						newObj.add(oldObj.get(sitd.getFieldName()));
					}
				}else {
					newObj.add("");
				}
				
			}
			resultList.add(newObj);
		}
		return resultList;
	}
	
	public void filterDictText(Map<String,String> dictMap,List<Object> dictList,String fieldValue,String itexText,String itexValue) {
		JSONObject dictObj = null;
		for(int i=0; i<dictList.size();i++) {
			dictObj = JSONObject.parseObject(JSON.toJSONString(dictList.get(i)));
			dictMap.put(dictObj.getString(itexValue), dictObj.getString(itexText));
			if(dictObj.containsKey("children")) {
				//如果是树
				filterDictText(dictMap, dictObj.getJSONArray("children"), fieldValue, itexText, itexValue);
			}
		}
	}
	
	/**
	 * 模板下载，生成标题
	 * @param templateDetailList
	 * @return
	 */
	private List<List<String>> templateHead(List<SysImportTemplateDetail> templateDetailList) {
		List<List<String>> list = new ArrayList<List<String>>();
		for(SysImportTemplateDetail sitd : templateDetailList) {
			List<String> h = new ArrayList<>();
			h.add(sitd.getFieldTitle());
			list.add(h);
		}
		return list;
	}
	
	/**
	 * 模板下载
	 * @param request
	 * @param response
	 */
	@GetMapping(value = "/downloadTemplate")
	public void downloadTemplate(HttpServletRequest request, HttpServletResponse response) {

		try {

			String templateId = request.getParameter("templateId");
			String templateName = request.getParameter("templateName");
			if (StringUtils.isEmpty(templateId) || StringUtils.isEmpty(templateName)) {
				downloadException(response, "请指定数据模板");
				return;
			}
			
			List<SysImportTemplateDetail> templateDetailList = iSysImportTemplateDetailService.querytemplateDetailByTemplateId(templateId,RightConstants.是.getCode());
			if(templateDetailList==null || templateDetailList.size()==0) {
				downloadException(response, "模板信息不存在，请确认");
				return;
			}
			
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			String fileName = URLEncoder.encode(templateName, "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			EasyExcel.write(response.getOutputStream()).head(templateHead(templateDetailList)).autoCloseStream(Boolean.FALSE).sheet().registerWriteHandler(new ExcelWidthStyleStrategy()).doWrite(null);
		} catch (Exception e) {
			downloadException(response, e.getMessage());
		}

	}

	/**
	 * 文件下载失败
	 * @param response
	 * @param mes
	 */
	private void downloadException(HttpServletResponse response,String mes) {
		// 重置response
		response.reset();
		response.setContentType("application/json");
		response.setCharacterEncoding("utf-8");
		Map<String, String> map = new HashMap<String, String>();
		map.put("message", "下载文件失败:" + mes);
		try {
			response.getWriter().println(JSON.toJSONString(map));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
}
